home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fsio / fsioDevice.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  54KB  |  1,701 lines

  1. /* 
  2.  * fsDevice.c --
  3.  *
  4.  *    Routines to manage devices.  
  5.  *    The handle for a device is uniquified using the device type and
  6.  *    unit number.  This ensures that different filesystem names for
  7.  *    the same device map to the same device I/O handle.
  8.  *
  9.  *    There are two sets of routines here.  There are routines internal
  10.  *    to the filesystem that are used to open, close, read, write, etc.
  11.  *    a device stream.  Then there are some external routines exported
  12.  *    for use by device drivers.  Fs_NotifyReader and Fs_NotifyWriter
  13.  *    are used by interrupt handlers to indicate a device is ready.
  14.  *    Then there are a handful of conversion routines for mapping
  15.  *    from file system block numbers to disk addresses.
  16.  *
  17.  * Copyright 1987 Regents of the University of California
  18.  * All rights reserved.
  19.  * Permission to use, copy, modify, and distribute this
  20.  * software and its documentation for any purpose and without
  21.  * fee is hereby granted, provided that the above copyright
  22.  * notice appear in all copies.  The University of California
  23.  * makes no representations about the suitability of this
  24.  * software for any purpose.  It is provided "as is" without
  25.  * express or implied warranty.
  26.  */
  27.  
  28. #ifndef lint
  29. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fsio/fsioDevice.c,v 9.15 92/10/26 14:02:04 mgbaker Exp $ SPRITE (Berkeley)";
  30. #endif not lint
  31.  
  32.  
  33. #include <sprite.h>
  34.  
  35. #include <fs.h>
  36. #include <fsutil.h>
  37. #include <fsconsist.h>
  38. #include <fsio.h>
  39. #include <fsNameOps.h>
  40. #include <fsdm.h>
  41. #include <fsioLock.h>
  42. #include <fsprefix.h>
  43. #include <fsrmt.h>
  44. #include <dev.h>
  45. #include <rpc.h>
  46. #include <fsStat.h>
  47. #include <fsioDevice.h>
  48. #include <devFsOpTable.h>
  49. #include <devTypes.h>
  50.  
  51. #include <stdio.h>
  52. #include <fsrecov.h>
  53. #include <recov.h>
  54. #include <vmMach.h>
  55.  
  56. /*
  57.  * INET is defined so a file server can be used to open the
  58.  * special device file corresponding to a kernel-based ipServer
  59.  */
  60. #undef INET
  61. #ifdef INET
  62. #include <netInet.h>
  63. /*
  64.  * DEV_PLACEHOLDER_2    is defined in devTypesInt.h, which is not exported.
  65.  *    This is an ugly hack, anyway, so we just define it here.  3/89
  66.  *    The best solution is to define a new disk file type and not
  67.  *    use Fsio_DeviceNameOpen at all.
  68.  */
  69. #define DEV_PLACEHOLDER_2    3
  70. static int sockCounter = 0;
  71. #endif
  72.  
  73. static void ReadNotify _ARGS_((ClientData data, Proc_CallInfo *callInfoPtr));
  74. static void WriteNotify _ARGS_((ClientData data, Proc_CallInfo *callInfoPtr));
  75. static void ExceptionNotify _ARGS_((ClientData data, 
  76.                 Proc_CallInfo *callInfoPtr));
  77.  
  78. extern ReturnStatus FsioDeviceCloseInt _ARGS_((
  79.         Fsio_DeviceIOHandle *devHandlePtr, int useFlags, int refs, 
  80.         int writes));
  81.  
  82.  
  83.  
  84. /*
  85.  *----------------------------------------------------------------------
  86.  *
  87.  * FsioDeviceHandleInit --
  88.  *
  89.  *    Initialize a handle for a local device.
  90.  *
  91.  * Results:
  92.  *    TRUE if the handle was already found, FALSE if not.
  93.  *
  94.  * Side effects:
  95.  *    Create and install a handle for the device.  It is returned locked
  96.  *    and with its reference count incremented if SUCCESS is returned.
  97.  *
  98.  *----------------------------------------------------------------------
  99.  */
  100. Boolean
  101. FsioDeviceHandleInit(fileIDPtr, name, newHandlePtrPtr)
  102.     Fs_FileID        *fileIDPtr;
  103.     char        *name;
  104.     Fsio_DeviceIOHandle    **newHandlePtrPtr;
  105. {
  106.     register Boolean found;
  107.     register Fsio_DeviceIOHandle *devHandlePtr;
  108.  
  109.     found = Fsutil_HandleInstall(fileIDPtr, sizeof(Fsio_DeviceIOHandle), name,
  110.             FALSE, (Fs_HandleHeader **)newHandlePtrPtr);
  111.     if (!found) {
  112.     devHandlePtr = *newHandlePtrPtr;
  113.     List_Init(&devHandlePtr->clientList);
  114.     devHandlePtr->use.ref = 0;
  115.     devHandlePtr->use.write = 0;
  116.     devHandlePtr->use.exec = 0;
  117.     devHandlePtr->device.serverID = fileIDPtr->serverID;
  118.     devHandlePtr->device.type = fileIDPtr->major;
  119.     devHandlePtr->device.unit = fileIDPtr->minor;
  120.     devHandlePtr->device.data = (ClientData)NIL;
  121.     devHandlePtr->flags = 0;
  122.     Fsio_LockInit(&devHandlePtr->lock);
  123.     devHandlePtr->modifyTime = 0;
  124.     devHandlePtr->accessTime = 0;
  125.     List_Init(&devHandlePtr->readWaitList);
  126.     List_Init(&devHandlePtr->writeWaitList);
  127.     List_Init(&devHandlePtr->exceptWaitList);
  128.     devHandlePtr->notifyFlags = 0;
  129.     fs_Stats.object.devices++;
  130.     }
  131.     return(found);
  132. }
  133.  
  134.  
  135. /*
  136.  *----------------------------------------------------------------------
  137.  *
  138.  * Fsio_DeviceNameOpen --
  139.  *
  140.  *    This routine sets up an ioFileID for the device based on the
  141.  *    device file found on the name server.  This is called on the name
  142.  *    server in two cases, when a client is doing an open, and when
  143.  *    it is doing a Get/Set attributes on a device file name.   At
  144.  *    open time some additional attributes are returned to the client
  145.  *    for caching at the I/O server, and a streamID is chosen.
  146.  *    Note that no state is kept about the device client here on the
  147.  *    name server.  The device client open routine sets up that state.
  148.  *
  149.  * Results:
  150.  *    SUCCESS, *ioFileIDPtr has the I/O file ID, and *clientDataPtr
  151.  *    references the device state.
  152.  *
  153.  * Side effects:
  154.  *    Choose the fileID for the clients stream.
  155.  *    Allocates memory to hold the stream data.
  156.  *
  157.  *----------------------------------------------------------------------
  158.  */
  159. /*ARGSUSED*/
  160. ReturnStatus
  161. Fsio_DeviceNameOpen(handlePtr, openArgsPtr, openResultsPtr)
  162.     Fsio_FileIOHandle    *handlePtr;    /* A handle obtained by FslclLookup.
  163.                      * Should be locked upon entry,
  164.                      * is unlocked upon exit. */
  165.      Fs_OpenArgs        *openArgsPtr;    /* Standard open arguments */
  166.      Fs_OpenResults    *openResultsPtr;/* For returning ioFileID, streamID,
  167.                      * and Fsio_DeviceState */
  168. {
  169.     register Fsdm_FileDescriptor *descPtr = handlePtr->descPtr;
  170.     register Fsio_DeviceState *deviceDataPtr;
  171.     register Fs_FileID *ioFileIDPtr = &openResultsPtr->ioFileID;
  172.  
  173.     ioFileIDPtr->serverID = descPtr->devServerID;
  174.     if (ioFileIDPtr->serverID == FS_LOCALHOST_ID) {
  175.     /*
  176.      * Map this "common" or "generic" device to the instance of
  177.      * the device on the process's logical home node.
  178.      */
  179.     ioFileIDPtr->serverID = openArgsPtr->migClientID;
  180.     }
  181.     ioFileIDPtr->major = descPtr->devType;
  182.     ioFileIDPtr->minor = descPtr->devUnit;
  183. #ifdef INET
  184.     /*
  185.      * Hack in support for sockets by mapping a special device type
  186.      * to sockets.  This needs to be replaced with a new type of disk file.
  187.      */
  188.     if (descPtr->devType == DEV_PLACEHOLDER_2) {
  189.     ioFileIDPtr->major = rpc_SpriteID;
  190.     ioFileIDPtr->minor = sockCounter++;
  191.     switch(descPtr->devUnit) {
  192.         case NET_IP_PROTOCOL_IP:
  193.         ioFileIDPtr->type = FSIO_RAW_IP_STREAM;
  194.         break;
  195.         case NET_IP_PROTOCOL_UDP:
  196.         ioFileIDPtr->type = FSIO_UDP_STREAM;
  197.         break;
  198.         case NET_IP_PROTOCOL_TCP:
  199.         ioFileIDPtr->type = FSIO_TCP_STREAM;
  200.         break;
  201.         default:
  202.         ioFileIDPtr->major = descPtr->devType;
  203.         ioFileIDPtr->minor = descPtr->devUnit;
  204.         if (ioFileIDPtr->serverID == openArgsPtr->clientID) {
  205.             ioFileIDPtr->type = FSIO_LCL_DEVICE_STREAM;
  206.         } else {
  207.             ioFileIDPtr->type = FSIO_RMT_DEVICE_STREAM;
  208.         }
  209.         break;
  210.     }
  211.     } else
  212. #endif
  213.     if (ioFileIDPtr->serverID == openArgsPtr->clientID) {
  214.     ioFileIDPtr->type = FSIO_LCL_DEVICE_STREAM;
  215.     } else {
  216.     ioFileIDPtr->type = FSIO_RMT_DEVICE_STREAM;
  217.     }
  218.     if (openArgsPtr->useFlags != 0) {
  219.     /*
  220.      * Truely preparing for an open.
  221.      * Return the current modify/access times for the I/O server's cache.
  222.      */
  223.     deviceDataPtr = mnew(Fsio_DeviceState);
  224.     deviceDataPtr->modifyTime = descPtr->dataModifyTime;
  225.     deviceDataPtr->accessTime = descPtr->accessTime;
  226.     /*
  227.      * Choose a streamID for the client that points to the device server.
  228.      */
  229.     Fsio_StreamCreateID(ioFileIDPtr->serverID, &openResultsPtr->streamID);
  230.     deviceDataPtr->streamID = openResultsPtr->streamID;
  231.  
  232.     openResultsPtr->streamData = (ClientData)deviceDataPtr;
  233.     openResultsPtr->dataSize = sizeof(Fsio_DeviceState);
  234.     }
  235.     Fsutil_HandleUnlock(handlePtr);
  236.     return(SUCCESS);
  237. }
  238.  
  239. /*
  240.  *----------------------------------------------------------------------
  241.  *
  242.  * Fsio_DeviceIoOpen --
  243.  *
  244.  *    Complete opening of a local device.  This is called on the I/O
  245.  *    server and sets up state concerning this client.  The device
  246.  *    driver open routine is called to set up the device.  If that
  247.  *    succeeds then the device's Handle is installed and set up.
  248.  *    This includes incrementing client's use counts and the
  249.  *    global use counts in the handle.
  250.  *
  251.  * Results:
  252.  *    SUCCESS or a device dependent open error code.
  253.  *
  254.  * Side effects:
  255.  *    Sets up and installs the device's ioHandle.  The device-type open
  256.  *    routine is called on the I/O server.  The handle is unlocked
  257.  *    upon exit, but its reference count has been incremented.
  258.  *
  259.  *----------------------------------------------------------------------
  260.  */
  261. ReturnStatus
  262. Fsio_DeviceIoOpen(ioFileIDPtr, flagsPtr, clientID, streamData, name, ioHandlePtrPtr)
  263.     register Fs_FileID    *ioFileIDPtr;    /* I/O fileID */
  264.     int            *flagsPtr;    /* FS_READ | FS_WRITE ... */
  265.     int            clientID;    /* Host doing the open */
  266.     ClientData        streamData;    /* Reference to Fsio_DeviceState struct */
  267.     char        *name;        /* File name for error msgs */
  268.     Fs_HandleHeader    **ioHandlePtrPtr;/* Return - a locked handle set up for
  269.                      * I/O to a device, NIL if failure. */
  270. {
  271.     ReturnStatus         status;
  272.     Boolean            found;
  273.     register Fsio_DeviceState    *deviceDataPtr;
  274.     register Fsio_DeviceIOHandle    *devHandlePtr;
  275.     Fsio_DeviceIOHandle        *tDevHandlePtr;    /* tempory devHandlePtr */
  276.     register Fs_Stream        *streamPtr;
  277.     register int        flags = *flagsPtr;
  278.  
  279.     deviceDataPtr = (Fsio_DeviceState *)streamData;
  280.     *ioHandlePtrPtr = (Fs_HandleHeader *)NIL;
  281.  
  282.     found = FsioDeviceHandleInit(ioFileIDPtr, name, &tDevHandlePtr);
  283.     devHandlePtr = tDevHandlePtr;
  284.     /*
  285.      * The device driver open routine gets the device specification,
  286.      * the useFlags, and a token passed to Fs_NotifyReader
  287.      * or Fs_NotifyWriter when the device becomes ready for I/O.
  288.      */
  289.     if (DEV_TYPE_INDEX(devHandlePtr->device.type) >= devNumDevices) {
  290.     status = FS_DEVICE_OP_INVALID;
  291.     } else {
  292.     status = (*devFsOpTable[DEV_TYPE_INDEX(devHandlePtr->device.type)].open)
  293.             (&devHandlePtr->device, flags, 
  294.              (Fs_NotifyToken)devHandlePtr, &devHandlePtr->flags);
  295.     }
  296.     if (status == SUCCESS) {
  297.     if (!found) {
  298.         /*
  299.          * Absorb the I/O attributes returned from the SrvOpen routine
  300.          * on the file server.
  301.          */
  302.         devHandlePtr->modifyTime = deviceDataPtr->modifyTime;
  303.         devHandlePtr->accessTime = deviceDataPtr->accessTime;
  304.     }
  305.     /*
  306.      * Trace the client, and then update our overall use counts.
  307.      * The client is recorded at the stream level to support migration,
  308.      * and at the I/O handle level for regular I/O.
  309.      */
  310.     (void)Fsconsist_IOClientOpen(&devHandlePtr->clientList, clientID, flags, FALSE);
  311.  
  312.     streamPtr = Fsio_StreamAddClient(&deviceDataPtr->streamID, clientID,
  313.             (Fs_HandleHeader *)devHandlePtr, flags,
  314.             name, (Boolean *)NIL, (Boolean *)NIL);
  315.     Fsutil_HandleRelease(streamPtr, TRUE);
  316.  
  317.     devHandlePtr->use.ref++;
  318.     if (flags & FS_WRITE) {
  319.         devHandlePtr->use.write++;
  320.     }
  321.     *ioHandlePtrPtr = (Fs_HandleHeader *)devHandlePtr;
  322.     /*
  323.      * Add the handles to the recovery box only if it's a remote request.
  324.      */
  325.     if (recov_Transparent && clientID != rpc_SpriteID) {
  326.         status = Fsrecov_AddHandle((Fs_HandleHeader *) devHandlePtr,
  327.             (Fs_FileID *) NIL, clientID, flags, FALSE, TRUE);
  328.         /* We'll have to do better than this! */
  329.         if (status != SUCCESS) {
  330.         panic("Fsio_DeviceIoOpen: couldn't add handle to recov box.");
  331.         }
  332.         /*
  333.          * Now add mapping between stream and ioHandle.  We'll need to
  334.          * handle error cases better!!
  335.          */
  336.         status = Fsrecov_AddHandle((Fs_HandleHeader *) streamPtr,
  337.             (Fs_FileID *) &((Fs_HandleHeader *) devHandlePtr)->fileID,
  338.             clientID, streamPtr->flags, streamPtr->offset, TRUE);
  339.         if (status != SUCCESS) {
  340.         panic("Fsio_DeviceIoOpen: couldn't add stream to recov box.");
  341.         }
  342.     }
  343.     Fsutil_HandleUnlock(devHandlePtr);
  344.     } else {
  345.     Fsutil_HandleRelease(devHandlePtr, TRUE);
  346.     }
  347.     free((Address) deviceDataPtr);
  348.     return(status);
  349. }
  350.  
  351. /*
  352.  *----------------------------------------------------------------------
  353.  *
  354.  * Fsio_DeviceClose --
  355.  *
  356.  *    Close a stream to a device.  We just need to clean up our state with
  357.  *    the device driver.  The file server that named the device file keeps
  358.  *    no state about us, so we don't have to contact it.
  359.  *
  360.  * FIX ME: need to write back access/modify times to name server
  361.  *    Can use fs_AttrOpTable and the nameInfoPtr->fileID as long
  362.  *    if the shadow stream on the I/O server is set up enough.
  363.  *
  364.  * Results:
  365.  *    SUCCESS.
  366.  *
  367.  * Side effects:
  368.  *    Calls the device type close routine.
  369.  *
  370.  *----------------------------------------------------------------------
  371.  */
  372. /*ARGSUSED*/
  373. ReturnStatus
  374. Fsio_DeviceClose(streamPtr, clientID, procID, flags, size, data)
  375.     Fs_Stream        *streamPtr;    /* Stream to device */
  376.     int            clientID;    /* HostID of client closing */
  377.     Proc_PID        procID;        /* ID of closing process */
  378.     int            flags;        /* Flags from the stream being closed */
  379.     int            size;        /* Should be zero */
  380.     ClientData        data;        /* IGNORED */
  381. {
  382.     ReturnStatus        status;
  383.     register Fsio_DeviceIOHandle    *devHandlePtr =
  384.         (Fsio_DeviceIOHandle *)streamPtr->ioHandlePtr;
  385.     Boolean            cache = FALSE;
  386.  
  387.     if (!Fsconsist_IOClientClose(&devHandlePtr->clientList, clientID, flags, &cache)) {
  388.     printf("Fsio_DeviceClose, client %d unknown for device <%d,%d>\n",
  389.           clientID, devHandlePtr->hdr.fileID.major,
  390.           devHandlePtr->hdr.fileID.minor);
  391.     Fsutil_HandleRelease(devHandlePtr, TRUE);
  392.     return(FS_STALE_HANDLE);
  393.     }
  394.     /*
  395.      * Clean up locks, then
  396.      * clean up summary use counts and call driver's close routine.
  397.      */
  398.     Fsio_LockClose(&devHandlePtr->lock, &streamPtr->hdr.fileID);
  399.  
  400.     status = FsioDeviceCloseInt(devHandlePtr, flags, 1, (flags & FS_WRITE) != 0);
  401.     if (recov_Transparent && status == SUCCESS &&
  402.         clientID != rpc_SpriteID) {
  403.     if (Fsrecov_DeleteHandle((Fs_HandleHeader *) devHandlePtr, clientID,
  404.         flags) != SUCCESS) {
  405.         /* We'll have to do better than this! */
  406.         panic(
  407.         "Fsio_DeviceClose: couldn't remove handle from recov box.");
  408.     }
  409.     if (Fsrecov_DeleteHandle((Fs_HandleHeader *) streamPtr, clientID,
  410.         streamPtr->flags) != SUCCESS) {
  411.         /* We'll have to do better than this! */
  412.         panic(
  413.         "Fsio_DeviceClose: couldn't remove stream from recov box.");
  414.     }
  415.     }
  416.     /*
  417.      * We don't bother to remove the handle here if the device isn't
  418.      * being used.  Instead we let the handle get scavenged.
  419.      */
  420.     Fsutil_HandleRelease(devHandlePtr, TRUE);
  421.  
  422.     return(status);
  423. }
  424.  
  425. /*
  426.  *----------------------------------------------------------------------
  427.  *
  428.  * Fsio_DeviceReopen --
  429.  *
  430.  *    Reopen a device here on the I/O server.
  431.  *
  432.  * Results:
  433.  *    None.
  434.  *
  435.  * Side effects:
  436.  *    None.
  437.  *    
  438.  *
  439.  *----------------------------------------------------------------------
  440.  */
  441. /*ARGSUSED*/
  442. ReturnStatus
  443. Fsio_DeviceReopen(hdrPtr, clientID, inData, outSizePtr, outDataPtr)
  444.     Fs_HandleHeader    *hdrPtr;    /* NIL on the I/O server */
  445.     int            clientID;    /* Client doing the reopen */
  446.     ClientData        inData;        /* Ref. to Fsio_DeviceReopenParams */
  447.     int            *outSizePtr;    /* Size of returned data, 0 here */
  448.     ClientData        *outDataPtr;    /* Returned data, NIL here */
  449. {
  450.     Fsio_DeviceIOHandle    *devHandlePtr;
  451.     ReturnStatus    status;
  452.     register        devIndex;
  453.     register Fsio_DeviceReopenParams *paramPtr =
  454.         (Fsio_DeviceReopenParams *)inData;
  455.     Fsrecov_HandleState    recovInfo;
  456.     Boolean    found;
  457.  
  458.     *outDataPtr = (ClientData) NIL;
  459.     *outSizePtr = 0;
  460.  
  461.     /*
  462.      * Old clients still do reopens of devices with no references, so
  463.      * protect ourselves on the server.
  464.      */
  465.     if (paramPtr->use.ref == 0) {
  466.     return SUCCESS;
  467.     }
  468.     found = FsioDeviceHandleInit(¶mPtr->fileID, (char *)NIL, &devHandlePtr); 
  469.  
  470.     devIndex = DEV_TYPE_INDEX(devHandlePtr->device.type);
  471.     if (devIndex >= devNumDevices) {
  472.     status = FS_DEVICE_OP_INVALID;
  473.         Fsutil_HandleRelease(devHandlePtr, TRUE);
  474.         return(status);
  475.     }
  476.  
  477.     /* If this is a fast restart, we can look at recov box contents. */
  478.     if (recov_Transparent && fsrecov_AlreadyInit) {
  479.         Fs_FileID       fid;
  480.  
  481.         printf("Device Reopen, looking for file %d.%d.%d.%d\n",
  482.                 fid.type, fid.serverID, fid.major, fid.minor);
  483.         fid = paramPtr->fileID;
  484.     if (!found) {
  485.         panic(
  486.         "Fsio_DeviceReopen: handle %d.%d.%d.%d  wasn't initialized.\n",
  487.             fid.type, fid.serverID, fid.major, fid.minor);
  488.     }
  489.         /* Get info from recov box. */
  490.         status = Fsrecov_GetHandle(fid, clientID, &recovInfo, TRUE);
  491.         if (status != SUCCESS) {
  492.             panic("Fsio_DeviceReopen: couldn't get recov info for handle.");
  493.         }
  494.         /* Test it for sameness. */
  495.         if ((recovInfo.fileID.major != paramPtr->fileID.major) ||
  496.                 (recovInfo.fileID.minor != paramPtr->fileID.minor)) {
  497.             panic("Fsio_DeviceReopen: major or minor numbers disagree.");
  498.         }
  499.         if (recovInfo.use.ref != paramPtr->use.ref) {
  500.             panic("Fsio_DeviceReopen: refs disagree.");
  501.         }
  502.         if (recovInfo.use.write != paramPtr->use.write) {
  503.             panic("Fsio_DeviceReopen: write refs disagree.");
  504.         }
  505.         if (recovInfo.use.exec != paramPtr->use.exec) {
  506.             panic("Fsio_DeviceReopen: exec refs disagree.");
  507.         }
  508.     /*
  509.      * Use what we got from the recovery box to return to the client.
  510.      */
  511.     if (fsrecov_FromBox) {
  512.         return SUCCESS;        /* No outData for device reopen. */
  513.     }
  514.     }
  515.  
  516.     /*
  517.      * Compute the difference between the client's and our version
  518.      * of the client's use state, and then call the device driver
  519.      * with that information.  We may have missed opens (across a
  520.      * reboot) or closes (during transient communication failures)
  521.      * so the net difference may be positive or negative.
  522.      */
  523.     Fsconsist_IOClientStatus(&devHandlePtr->clientList, clientID, ¶mPtr->use);
  524.     if (paramPtr->use.ref == 0) {
  525.     status = SUCCESS;    /* No change visible to driver */
  526.     } else if (paramPtr->use.ref > 0) {
  527.     /*
  528.      * Reestablish open connections.
  529.      */
  530.     status = (*devFsOpTable[devIndex].reopen)(&devHandlePtr->device,
  531.                 paramPtr->use.ref, paramPtr->use.write,
  532.                 (Fs_NotifyToken)devHandlePtr,
  533.                 &devHandlePtr->flags);
  534.     if (status == SUCCESS) {
  535.             Fsio_UseCounts      use;
  536.  
  537.             use.ref = paramPtr->use.ref;
  538.             use.write = paramPtr->use.write;
  539.             use.exec = 0;
  540.  
  541.         (void)Fsconsist_IOClientReopen(&devHandlePtr->clientList, clientID,
  542.                      ¶mPtr->use);
  543.         devHandlePtr->use.ref += paramPtr->use.ref;
  544.         devHandlePtr->use.write += paramPtr->use.write;
  545.             if (recov_Transparent && !fsrecov_AlreadyInit) {
  546.                 int         useFlags = FS_READ;
  547.                 Fs_FileID   fid;
  548.  
  549.                 fid = paramPtr->fileID;
  550.                 printf("Reopen Device, installing file %d.%d.%d.%d refs: %d\n",
  551.                         fid.type, fid.serverID, fid.major, fid.minor, use.ref);
  552.  
  553.                 /*
  554.                  * May have to call this more than once if paramPtr->use
  555.                  * has a ref count of more than 1.
  556.                  */
  557.                 while (use.ref > 0) {
  558.                     if (paramPtr->use.write) {
  559.                         useFlags |= FS_WRITE;
  560.                     }
  561.                     /* Add file handle to recov box. */
  562.                     status = Fsrecov_AddHandle((Fs_HandleHeader *) devHandlePtr,
  563.                 (Fs_FileID *) NIL, clientID, useFlags, FALSE, TRUE);
  564.                     useFlags = FS_READ;
  565.                     /* We'll have to do better than this! */
  566.                     if (status != SUCCESS) {
  567.                         panic("Fsio_DeviceReopen: couldn't add recov handle.");
  568.                     }
  569.                     use.ref--;
  570.                     if (use.write > 0) {
  571.                         use.write--;
  572.                     }
  573.                 }
  574.         /* Stream is added in stream reopen procedure. */
  575.             }
  576.             /*
  577.              * XXX Else, should I check ref counts to make sure nothing lost?
  578.              * Not for now, since if it's a fast restart, we check for
  579.              * differing ref counts above and panic.
  580.              */
  581.         }
  582.     } else {
  583.     /*
  584.      * Clean up closed connections.  Note, we assume that
  585.      * the client was reading, even though it may have had
  586.      * a write-only stream.  This could break syslog, which
  587.      * is a single-reader/multiple-writer stream.  "ref" should
  588.      * be changed to "read".
  589.      */
  590.     int useFlags = FS_READ;
  591.         Fsio_UseCounts  use;
  592.         Fs_FileID   fid;
  593.  
  594.         fid = paramPtr->fileID;
  595.         use.ref = paramPtr->use.ref;
  596.         use.write = paramPtr->use.write;
  597.         use.exec = 0;
  598.  
  599.     if (paramPtr->use.write > 0) {
  600.         useFlags |= FS_WRITE;
  601.     }
  602.     status = FsioDeviceCloseInt(devHandlePtr, useFlags, paramPtr->use.ref,
  603.                         paramPtr->use.write);
  604.     if (recov_Transparent) {
  605.         printf("Reopen Deleteing Device: %d.%d.%d.%d, refs: %d\n",
  606.             fid.type, fid.serverID, fid.major, fid.minor, use.ref);
  607.  
  608.         useFlags = FS_READ;
  609.         while (use.ref > 0) {
  610.         if (use.write > 0) {
  611.             useFlags |= FS_WRITE;
  612.         }
  613.         if (Fsrecov_DeleteHandle((Fs_HandleHeader *) devHandlePtr,
  614.             clientID, useFlags) != SUCCESS) {
  615.             /* We'll have to do better than this! */
  616.         panic("Fsio_DeviceReopen: couldn't remove handle from box.");
  617.         }
  618.         use.ref--;
  619.         if (use.write > 0) {
  620.             use.write--;
  621.         }
  622.         useFlags = FS_READ;
  623.         }
  624.     }
  625.     }
  626.  
  627.     Fsutil_HandleRelease(devHandlePtr, TRUE);
  628.     return(status);
  629. }
  630.  
  631.  
  632. /*
  633.  * ----------------------------------------------------------------------------
  634.  *
  635.  * FsioDeviceCloseInt --
  636.  *
  637.  *    Called internally to Fsio_DeviceClose to close a device.  Also
  638.  *    called from other places as needed.
  639.  *    
  640.  *
  641.  * Results:
  642.  *    SUCCESS.
  643.  *
  644.  * Side effects:
  645.  *    Adjusts the use counts on the file.  This unlocks the handle.
  646.  *
  647.  * ----------------------------------------------------------------------------
  648.  *
  649.  */
  650. ReturnStatus
  651. FsioDeviceCloseInt(devHandlePtr, useFlags, refs, writes)
  652.     Fsio_DeviceIOHandle *devHandlePtr;    /* Device handle */
  653.     int useFlags;            /* Flags from the stream */
  654.     int refs;                /* Number of refs to close */
  655.     int writes;                /* Number of these that were writing */
  656. {
  657.     if (refs > 0) {
  658.     devHandlePtr->use.ref -= refs;
  659.     }
  660.     if (writes > 0) {
  661.     devHandlePtr->use.write -= writes;
  662.     }
  663.  
  664.     if (devHandlePtr->use.ref < 0 || devHandlePtr->use.write < 0) {
  665.     panic("FsioDeviceCloseInt <%d,%d> ref %d, write %d\n",
  666.         devHandlePtr->hdr.fileID.major, devHandlePtr->hdr.fileID.minor,
  667.         devHandlePtr->use.ref, devHandlePtr->use.write);
  668.     }
  669.  
  670.     return (*devFsOpTable[DEV_TYPE_INDEX(devHandlePtr->device.type)].close)
  671.         (&devHandlePtr->device, useFlags, devHandlePtr->use.ref,
  672.         devHandlePtr->use.write);
  673. }
  674.  
  675. /*
  676.  * ----------------------------------------------------------------------------
  677.  *
  678.  * Fsio_DeviceClientKill --
  679.  *
  680.  *    Called when a client is assumed down.  This cleans up the
  681.  *    references due to the client.
  682.  *    
  683.  *
  684.  * Results:
  685.  *    SUCCESS.
  686.  *
  687.  * Side effects:
  688.  *    Removes the client list entry for the client and adjusts the
  689.  *    use counts on the file.  This unlocks the handle.
  690.  *
  691.  * ----------------------------------------------------------------------------
  692.  *
  693.  */
  694. /*ARGSUSED*/
  695. void
  696. Fsio_DeviceClientKill(hdrPtr, clientID)
  697.     Fs_HandleHeader    *hdrPtr;    /* File to clean up */
  698.     int            clientID;    /* Host assumed down */
  699. {
  700.     register Fsio_DeviceIOHandle *devHandlePtr = (Fsio_DeviceIOHandle *)hdrPtr;
  701.     int refs, writes, execs;
  702.     int    flags = FS_READ;    /* Might be wrong for syslog. */
  703.  
  704.     /*
  705.      * Remove the client from the list of users, and see what it was doing.
  706.      */
  707.     Fsconsist_IOClientKill(&devHandlePtr->clientList, clientID, &refs, &writes, &execs);
  708.  
  709.     Fsio_LockClientKill(&devHandlePtr->lock, clientID);
  710.  
  711.     if (refs > 0) {
  712.     int useFlags = FS_READ;        /* Have to assume this,
  713.                      * which might be wrong for syslog */
  714.     if (writes > 0) {
  715.         useFlags |= FS_WRITE;
  716.     }
  717.     if (fsrecov_DebugLevel >= 2) {
  718.         printf("Fsio_DeviceClientKill: deleting refs %d for %d.%d.%d.%d\n",
  719.             refs, hdrPtr->fileID.type, hdrPtr->fileID.serverID,
  720.             hdrPtr->fileID.major, hdrPtr->fileID.minor);
  721.     }
  722.     (void)FsioDeviceCloseInt(devHandlePtr, useFlags, refs, writes);
  723.     }
  724.     while (refs > 0) {
  725.         if (writes > 0) {
  726.             flags |= FS_WRITE;
  727.         }
  728.     if (recov_Transparent && clientID != rpc_SpriteID) {
  729.         if (Fsrecov_DeleteHandle((Fs_HandleHeader *) devHandlePtr, clientID,
  730.             flags) != SUCCESS) {
  731.         /* We'll have to do better than this! */
  732.         panic(
  733.         "Fsio_DeviceClientKill: couldn't remove handle from box.");
  734.         }
  735.         }
  736.         refs--;
  737.         if (writes > 0) {
  738.             writes--;
  739.         }
  740.         flags = FS_READ;
  741.     }
  742.  
  743.     Fsutil_HandleUnlock(devHandlePtr);
  744. }
  745.  
  746. /*
  747.  * ----------------------------------------------------------------------------
  748.  *
  749.  * Fsio_DeviceScavenge --
  750.  *
  751.  *    Called periodically to see if this handle is still needed.
  752.  *    
  753.  *
  754.  * Results:
  755.  *    TRUE if the handle was removed.
  756.  *
  757.  * Side effects:
  758.  *    Removes the handle if it isn't referenced anymore and there
  759.  *    are no remote clients.
  760.  *
  761.  * ----------------------------------------------------------------------------
  762.  *
  763.  */
  764. Boolean
  765. Fsio_DeviceScavenge(hdrPtr)
  766.     Fs_HandleHeader    *hdrPtr;    /* File to clean up */
  767. {
  768.     register Fsio_DeviceIOHandle *handlePtr = (Fsio_DeviceIOHandle *)hdrPtr;
  769.  
  770.     if (handlePtr->use.ref == 0) {
  771.     /*
  772.      * Remove handles for devices with no users.
  773.      */
  774.     Fsutil_WaitListDelete(&handlePtr->readWaitList);
  775.     Fsutil_WaitListDelete(&handlePtr->writeWaitList);
  776.     Fsutil_WaitListDelete(&handlePtr->exceptWaitList);
  777.     Fsutil_HandleRemove(handlePtr);
  778.     fs_Stats.object.devices--;
  779.     return(TRUE);
  780.     } else {
  781.         Fsutil_HandleUnlock(handlePtr);
  782.     return(FALSE);
  783.     }
  784. }
  785.  
  786. /*
  787.  *----------------------------------------------------------------------
  788.  *
  789.  * Fsio_VanillaDevReopen --
  790.  *
  791.  *    This is a simplified device driver re-open procedure.  It is called
  792.  *    from Fsrmt_DeviceReopen via the device operation switch.  It, in turn,
  793.  *    calls back through the device switch to the regular device open
  794.  *    procedure.  Form many simple devices this is sufficient for a reopen.
  795.  *
  796.  * Results:
  797.  *    None.
  798.  *
  799.  * Side effects:
  800.  *    None.
  801.  *    
  802.  *
  803.  *----------------------------------------------------------------------
  804.  */
  805. /*ARGSUSED*/
  806. ReturnStatus
  807. Fsio_VanillaDevReopen(devicePtr, refs, writes, notifyToken)
  808.     Fs_Device *devicePtr;    /* Identifies the device */
  809.     int refs;            /* Number of streams to the device */
  810.     int writes;            /* Number of those that are for writing */
  811.     Fs_NotifyToken notifyToken;    /* Used with Fsio_DevNotifyReader */
  812. {
  813.     int devIndex = DEV_TYPE_INDEX(devicePtr->type);
  814.     int useFlags = 0;
  815.     int flags;
  816.  
  817.     if (refs > 0) {
  818.     useFlags |= FS_READ;
  819.     }
  820.     if (writes > 0) {
  821.     useFlags |= FS_WRITE;
  822.     }
  823.     return((*devFsOpTable[devIndex].open)
  824.                 (devicePtr, useFlags, notifyToken, &flags));
  825. }
  826.  
  827. /*
  828.  * ----------------------------------------------------------------------------
  829.  *
  830.  * Fsio_DeviceMigClose --
  831.  *
  832.  *    Release a reference from a Device I/O handle.
  833.  *    
  834.  * Results:
  835.  *    SUCCESS.
  836.  *
  837.  * Side effects:
  838.  *    Release the I/O handle.
  839.  *
  840.  * ----------------------------------------------------------------------------
  841.  *
  842.  */
  843. /*ARGSUSED*/
  844. ReturnStatus
  845. Fsio_DeviceMigClose(hdrPtr, flags)
  846.     Fs_HandleHeader *hdrPtr;    /* File being encapsulated */
  847.     int flags;            /* Use flags from the stream */
  848. {
  849.     panic( "Fsio_DeviceMigClose called\n");
  850.     Fsutil_HandleRelease(hdrPtr, FALSE);
  851.     return(SUCCESS);
  852. }
  853.  
  854.  
  855. /*
  856.  * ----------------------------------------------------------------------------
  857.  *
  858.  * Fsio_DeviceMigrate --
  859.  *
  860.  *    This takes care of transfering references from one client to the other.
  861.  *    A useful side-effect of this routine is    to properly set the type in
  862.  *    the ioFileID, either FSIO_LCL_DEVICE_STREAM or FSIO_RMT_DEVICE_STREAM.
  863.  *    In the latter case FsRmtDevoceMigrate is called to do all the work.
  864.  *
  865.  * Results:
  866.  *    An error status if the I/O handle can't be set-up.
  867.  *    Otherwise SUCCESS is returned, *flagsPtr may have the FS_RMT_SHARED
  868.  *    bit set, and *sizePtr and *dataPtr are set to reference Fsio_DeviceState.
  869.  *
  870.  * Side effects:
  871.  *    Sets the correct stream type on the ioFileID.
  872.  *    Shifts client references from the srcClient to the destClient.
  873.  *    Set up and return Fsio_DeviceState for use by the MigEnd routine.
  874.  *
  875.  * ----------------------------------------------------------------------------
  876.  *
  877.  */
  878. /*ARGSUSED*/
  879. ReturnStatus
  880. Fsio_DeviceMigrate(migInfoPtr, dstClientID, flagsPtr, offsetPtr, sizePtr, dataPtr)
  881.     Fsio_MigInfo    *migInfoPtr;    /* Migration state */
  882.     int        dstClientID;    /* ID of target client */
  883.     int        *flagsPtr;    /* In/Out Stream usage flags */
  884.     int        *offsetPtr;    /* Return - new stream offset */
  885.     int        *sizePtr;    /* Return - sizeof(Fsio_DeviceState) */
  886.     Address    *dataPtr;    /* Return - pointer to Fsio_DeviceState */
  887. {
  888.     Fsio_DeviceIOHandle            *devHandlePtr;
  889.     Boolean                closeSrcClient;
  890.  
  891.     if (migInfoPtr->ioFileID.serverID != rpc_SpriteID) {
  892.     /*
  893.      * The device was local, which is why we were called, but is now remote.
  894.      */
  895.     migInfoPtr->ioFileID.type = FSIO_RMT_DEVICE_STREAM;
  896.     return(FsrmtDeviceMigrate(migInfoPtr, dstClientID, flagsPtr, offsetPtr,
  897.         sizePtr, dataPtr));
  898.     }
  899.     migInfoPtr->ioFileID.type = FSIO_LCL_DEVICE_STREAM;
  900.     if (!FsioDeviceHandleInit(&migInfoPtr->ioFileID, (char *)NIL, &devHandlePtr)){
  901.     printf(
  902.         "Fsio_DeviceMigrate, I/O handle <%d,%d> not found\n",
  903.          migInfoPtr->ioFileID.major, migInfoPtr->ioFileID.minor);
  904.     return(FS_FILE_NOT_FOUND);
  905.     }
  906.     /*
  907.      * At the stream level, add the new client to the set of clients
  908.      * for the stream, and check for any cross-network stream sharing.
  909.      */
  910.     Fsio_StreamMigClient(migInfoPtr, dstClientID, (Fs_HandleHeader *)devHandlePtr,
  911.             &closeSrcClient);
  912.     /*
  913.      * Adjust use counts on the I/O handle to reflect any new sharing.
  914.      */
  915.     Fsio_MigrateUseCounts(migInfoPtr->flags, closeSrcClient, &devHandlePtr->use);
  916.  
  917.     /*
  918.      * Move the client at the I/O handle level.
  919.      */
  920.     Fsio_MigrateClient(&devHandlePtr->clientList, migInfoPtr->srcClientID,
  921.             dstClientID, migInfoPtr->flags, closeSrcClient);
  922.     if (recov_Transparent && closeSrcClient &&
  923.         migInfoPtr->srcClientID != rpc_SpriteID) {
  924.     if (Fsrecov_DeleteHandle((Fs_HandleHeader *) devHandlePtr,
  925.         migInfoPtr->srcClientID, migInfoPtr->flags) != SUCCESS) {
  926.         /* Do better than this. */
  927.         panic("Fsio_DeviceMigrate: couldn't delete ioHandle from box.");
  928.     }
  929.     }
  930.     if (recov_Transparent && (migInfoPtr->flags & FS_NEW_STREAM) &&
  931.         dstClientID != rpc_SpriteID) {
  932.     if (Fsrecov_AddHandle((Fs_HandleHeader *) devHandlePtr,
  933.         (Fs_FileID *) NIL, dstClientID,
  934.         migInfoPtr->flags & ~FS_NEW_STREAM, FALSE, TRUE) != SUCCESS) {
  935.         /* Do better. */
  936.         panic("Fsio_DeviceMigrate: couldn't add ioHandle to box.");
  937.     }
  938.  
  939.     }
  940.  
  941.     *sizePtr = 0;
  942.     *dataPtr = (Address)NIL;
  943.     *flagsPtr = migInfoPtr->flags;
  944.     *offsetPtr = migInfoPtr->offset;
  945.     /*
  946.      * We don't need this reference on the I/O handle; there is no change.
  947.      */
  948.     Fsutil_HandleRelease(devHandlePtr, TRUE);
  949.     return(SUCCESS);
  950. }
  951.  
  952. /*
  953.  * ----------------------------------------------------------------------------
  954.  *
  955.  * Fsio_DeviceMigOpen --
  956.  *
  957.  *    Complete setup of a FS_DEVICE_STREAM after migration to the I/O server.
  958.  *    The migrate routine has done the work of shifting use counts
  959.  *    at the stream and I/O handle level.  This routine's job is
  960.  *    to increment the low level I/O handle reference count to reflect
  961.  *    the existence of a new stream to the I/O handle.
  962.  *
  963.  * Results:
  964.  *    None.
  965.  *
  966.  * Side effects:
  967.  *    None.
  968.  *
  969.  * ----------------------------------------------------------------------------
  970.  *
  971.  */
  972. /*ARGSUSED*/
  973. ReturnStatus
  974. Fsio_DeviceMigOpen(migInfoPtr, size, data, hdrPtrPtr)
  975.     Fsio_MigInfo    *migInfoPtr;    /* Migration state */
  976.     int        size;        /* Zero */
  977.     ClientData    data;        /* NIL */
  978.     Fs_HandleHeader **hdrPtrPtr;    /* Return - handle for the file */
  979. {
  980.     register Fsio_DeviceIOHandle *devHandlePtr;
  981.  
  982.     devHandlePtr = Fsutil_HandleFetchType(Fsio_DeviceIOHandle, &migInfoPtr->ioFileID);
  983.     if (devHandlePtr == (Fsio_DeviceIOHandle *)NIL) {
  984.     panic( "Fsio_DeviceMigOpen, no handlel\n");
  985.     return(FAILURE);
  986.     } else {
  987.     Fsutil_HandleUnlock(devHandlePtr);
  988.     *hdrPtrPtr = (Fs_HandleHeader *)devHandlePtr;
  989.     return(SUCCESS);
  990.     }
  991. }
  992.  
  993. /*
  994.  *----------------------------------------------------------------------
  995.  *
  996.  * Fsio_DeviceRead --
  997.  *
  998.  *      Read on a stream connected to a local peripheral device.
  999.  *    This branches to the driver routine after setting up buffers.
  1000.  *    This is called from Fs_Read and from Fsrmt_RpcRead.
  1001.  *
  1002.  * Results:
  1003.  *    SUCCESS unless there was an address error or I/O error.
  1004.  *
  1005.  * Side effects:
  1006.  *    Read the device.
  1007.  *
  1008.  *----------------------------------------------------------------------
  1009.  */
  1010. ReturnStatus
  1011. Fsio_DeviceRead(streamPtr, readPtr, remoteWaitPtr, replyPtr)
  1012.     Fs_Stream        *streamPtr;    /* Open stream to the device. */
  1013.     Fs_IOParam        *readPtr;    /* Read parameter block. */
  1014.     Sync_RemoteWaiter    *remoteWaitPtr;    /* Process info for remote waiting */
  1015.     Fs_IOReply        *replyPtr;    /* Signal to return, if any,
  1016.                      * plus the amount read. */
  1017. {
  1018.     register Fsio_DeviceIOHandle    *devHandlePtr =
  1019.         (Fsio_DeviceIOHandle *)streamPtr->ioHandlePtr;
  1020.     register ReturnStatus status;
  1021.     register Fs_Device    *devicePtr;
  1022.     int         flags;
  1023.     Address userBuffer;
  1024.     Boolean copy;
  1025.  
  1026.  
  1027.     userBuffer = (Address) NIL;
  1028.     flags = devHandlePtr->flags;
  1029.     /*
  1030.      * Don't lock if the device driver informed us upon open that 
  1031.      * it doesn't want it.
  1032.      */
  1033.     if (!(flags & FS_DEV_DONT_LOCK)) { 
  1034.     Fsutil_HandleLock(devHandlePtr);
  1035.     }
  1036.     /*
  1037.      * Because the read could take a while and we aren't mapping in
  1038.      * buffers, we have to allocate an extra buffer here so the
  1039.      * buffer address is valid when the device's interrupt handler
  1040.      * does its DMA. Don't do this malloc and copy if the device
  1041.      * driver said it would handle it.
  1042.      */
  1043.     if (VmMachIsXbusMem(readPtr->buffer)) {
  1044.     copy = 0;
  1045.     } else {
  1046.     copy = (readPtr->flags & FS_USER) && !(flags & FS_DEV_DONT_COPY);
  1047.     }
  1048.     if (copy) {
  1049.     userBuffer = readPtr->buffer;
  1050.     readPtr->buffer = (Address)malloc(readPtr->length);
  1051.     }
  1052.  
  1053.     /*
  1054.      * Put the process onto the read-wait list before attempting the read.
  1055.      * This is to prevent races with the device's notification which
  1056.      * happens from an interrupt handler.
  1057.      */
  1058.     Fsutil_WaitListInsert(&devHandlePtr->readWaitList, remoteWaitPtr);
  1059.     devicePtr = &devHandlePtr->device;
  1060.     status = (*devFsOpTable[DEV_TYPE_INDEX(devicePtr->type)].read)(devicePtr,
  1061.         readPtr, replyPtr);
  1062.     if (copy) {
  1063.         if (Vm_CopyOut(replyPtr->length, readPtr->buffer, userBuffer) != SUCCESS) {
  1064.         if (status == SUCCESS) {
  1065.         status = SYS_ARG_NOACCESS;
  1066.         }
  1067.     }
  1068.     free(readPtr->buffer);
  1069.     readPtr->buffer = userBuffer;
  1070.     }
  1071.     if (status != FS_WOULD_BLOCK) {
  1072.     Fsutil_WaitListRemove(&devHandlePtr->readWaitList, remoteWaitPtr);
  1073.     }
  1074.     devHandlePtr->accessTime = Fsutil_TimeInSeconds();
  1075.     fs_Stats.gen.deviceBytesRead += replyPtr->length;
  1076.     if (!(flags & FS_DEV_DONT_LOCK)) { 
  1077.     Fsutil_HandleUnlock(devHandlePtr);
  1078.     }
  1079.     return(status);
  1080. }
  1081.  
  1082. /*
  1083.  *----------------------------------------------------------------------
  1084.  *
  1085.  * Fsio_DeviceWrite --
  1086.  *
  1087.  *      Write on a stream connected to a local peripheral device.
  1088.  *    This is called from Fs_Write and Fsrmt_RpcWrite.
  1089.  *
  1090.  * Results:
  1091.  *    SUCCESS unless there was an address error or I/O error.
  1092.  *
  1093.  * Side effects:
  1094.  *    Write to the device.
  1095.  *
  1096.  *----------------------------------------------------------------------
  1097.  */
  1098. ReturnStatus
  1099. Fsio_DeviceWrite(streamPtr, writePtr, remoteWaitPtr, replyPtr)
  1100.     Fs_Stream        *streamPtr;    /* Open stream to the device. */
  1101.     Fs_IOParam        *writePtr;    /* Read parameter block */
  1102.     Sync_RemoteWaiter    *remoteWaitPtr;    /* Process info for remote waiting */
  1103.     Fs_IOReply        *replyPtr;    /* Signal to return, if any */
  1104. {
  1105.     register Fsio_DeviceIOHandle    *devHandlePtr =
  1106.         (Fsio_DeviceIOHandle *)streamPtr->ioHandlePtr;
  1107.     ReturnStatus    status = SUCCESS;
  1108.     register Fs_Device    *devicePtr = &devHandlePtr->device;
  1109.     Address        userBuffer;
  1110.     int            flags;
  1111.     Boolean        copy;
  1112.  
  1113.     userBuffer = (Address) NIL;
  1114.     flags = devHandlePtr->flags;
  1115.     /*
  1116.      * Don't lock if the device driver informed us upon open that 
  1117.      * it doesn't want it.
  1118.      */
  1119.     if (!(flags & FS_DEV_DONT_LOCK)) { 
  1120.     Fsutil_HandleLock(devHandlePtr);
  1121.     }
  1122.     /*
  1123.      * Because the write could take a while and we aren't mapping in
  1124.      * buffers, we have to allocate an extra buffer here so the
  1125.      * buffer address is valid when the device's interrupt handler
  1126.      * does its DMA. Don't do this malloc and copy if the device
  1127.      * driver said it would handle it.
  1128.      */
  1129.     if (VmMachIsXbusMem(writePtr->buffer)) {
  1130.     copy = 0;
  1131.     } else {
  1132.     copy = ((writePtr->flags & FS_USER) && !(flags & FS_DEV_DONT_COPY));
  1133.     }
  1134.     if (copy) {
  1135.     userBuffer = writePtr->buffer;
  1136.         writePtr->buffer = (Address)malloc(writePtr->length);
  1137.     if (Vm_CopyIn(writePtr->length, userBuffer, writePtr->buffer) != SUCCESS) {
  1138.         status = SYS_ARG_NOACCESS;
  1139.     }
  1140.     }
  1141.     if (status == SUCCESS) {
  1142.     /*
  1143.      * Put the process onto the write-wait list before attempting the write.
  1144.      * This is to prevent races with the device's notification which
  1145.      * happens from an interrupt handler.
  1146.      */
  1147.     Fsutil_WaitListInsert(&devHandlePtr->writeWaitList, remoteWaitPtr);
  1148.     status = (*devFsOpTable[DEV_TYPE_INDEX(devicePtr->type)].write)(devicePtr,
  1149.         writePtr, replyPtr);
  1150.     if (status != FS_WOULD_BLOCK) {
  1151.         Fsutil_WaitListRemove(&devHandlePtr->writeWaitList, remoteWaitPtr);
  1152.     }
  1153.     devHandlePtr->modifyTime = Fsutil_TimeInSeconds();
  1154.     fs_Stats.gen.deviceBytesWritten += replyPtr->length;
  1155.     }
  1156.  
  1157.     if (copy) {
  1158.     free(writePtr->buffer);
  1159.     writePtr->buffer = userBuffer;
  1160.     }
  1161.     if (!(flags & FS_DEV_DONT_LOCK)) { 
  1162.     Fsutil_HandleUnlock(devHandlePtr);
  1163.     }
  1164.     return(status);
  1165. }
  1166.  
  1167. /*
  1168.  *----------------------------------------------------------------------
  1169.  *
  1170.  * Fsio_DeviceSelect --
  1171.  *
  1172.  *      Select on a stream connected to a local peripheral device.  This
  1173.  *    ensures that the calling process is on a waiting list, then calls
  1174.  *    the device driver's select routine.  If the select succeeds, then
  1175.  *    the wait list items are removed.  The ordering of this is done to
  1176.  *    prevent races between the select routine and the notification that
  1177.  *    occurs at interrupt time.
  1178.  *
  1179.  * Results:
  1180.  *    A return from the driver, should be SUCCESS unless the
  1181.  *    device is offline or something.
  1182.  *
  1183.  * Side effects:
  1184.  *    None.
  1185.  *
  1186.  *----------------------------------------------------------------------
  1187.  */
  1188. ReturnStatus
  1189. Fsio_DeviceSelect(hdrPtr, waitPtr, readPtr, writePtr, exceptPtr)
  1190.     Fs_HandleHeader    *hdrPtr;    /* Handle on device to select */
  1191.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  1192.     int         *readPtr;    /* Bit to clear if non-readable */
  1193.     int         *writePtr;    /* Bit to clear if non-writeable */
  1194.     int         *exceptPtr;    /* Bit to clear if non-exceptable */
  1195. {
  1196.     register Fsio_DeviceIOHandle *devHandlePtr = (Fsio_DeviceIOHandle *)hdrPtr;
  1197.     register Fs_Device    *devicePtr = &devHandlePtr->device;
  1198.     register ReturnStatus status;
  1199.  
  1200.     Fsutil_HandleLock(devHandlePtr);
  1201.     if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  1202.     if (*readPtr) {
  1203.         Fsutil_WaitListInsert(&devHandlePtr->readWaitList, waitPtr);
  1204.     }
  1205.     if (*writePtr) {
  1206.         Fsutil_WaitListInsert(&devHandlePtr->writeWaitList, waitPtr);
  1207.     }
  1208.     if (*exceptPtr) {
  1209.         Fsutil_WaitListInsert(&devHandlePtr->exceptWaitList, waitPtr);
  1210.     }
  1211.     }
  1212.     status = (*devFsOpTable[DEV_TYPE_INDEX(devicePtr->type)].select)(devicePtr,
  1213.             readPtr, writePtr, exceptPtr);
  1214.     if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  1215.     if (*readPtr != 0) {
  1216.         Fsutil_WaitListRemove(&devHandlePtr->readWaitList, waitPtr);
  1217.     }
  1218.     if (*writePtr != 0) {
  1219.         Fsutil_WaitListRemove(&devHandlePtr->writeWaitList, waitPtr);
  1220.     }
  1221.     if (*exceptPtr != 0) {
  1222.         Fsutil_WaitListRemove(&devHandlePtr->exceptWaitList, waitPtr);
  1223.     }
  1224.     }
  1225.     Fsutil_HandleUnlock(devHandlePtr);
  1226.     return(status);
  1227. }
  1228.  
  1229. /*
  1230.  *----------------------------------------------------------------------
  1231.  *
  1232.  * Fsio_DeviceIOControl --
  1233.  *
  1234.  *      Write on a stream connected to a peripheral device.  Called from
  1235.  *    FsDomainWrite.
  1236.  *
  1237.  * Results:
  1238.  *    SUCCESS unless there was an address error or I/O error.
  1239.  *
  1240.  * Side effects:
  1241.  *    Write to the device.
  1242.  *
  1243.  *----------------------------------------------------------------------
  1244.  */
  1245. ReturnStatus
  1246. Fsio_DeviceIOControl(streamPtr, ioctlPtr, replyPtr)
  1247.     Fs_Stream *streamPtr;        /* Stream to a device. */
  1248.     Fs_IOCParam *ioctlPtr;        /* I/O Control parameter block */
  1249.     Fs_IOReply *replyPtr;        /* Return length and signal */
  1250. {
  1251.     register Fsio_DeviceIOHandle *devHandlePtr =
  1252.         (Fsio_DeviceIOHandle *)streamPtr->ioHandlePtr;
  1253.     register Fs_Device    *devicePtr = &devHandlePtr->device;
  1254.     register ReturnStatus status = SUCCESS;
  1255.  
  1256.     switch (ioctlPtr->command) {
  1257.     case IOC_LOCK:
  1258.     case IOC_UNLOCK:
  1259.         Fsutil_HandleLock(devHandlePtr);
  1260.         status = Fsio_IocLock(&devHandlePtr->lock, ioctlPtr,
  1261.             &streamPtr->hdr.fileID);
  1262.         Fsutil_HandleUnlock(devHandlePtr);
  1263.         break;
  1264.     case IOC_PREFIX:
  1265.         break;
  1266.     default:
  1267.         if (!(devHandlePtr->flags & FS_DEV_DONT_LOCK)) { 
  1268.         Fsutil_HandleLock(devHandlePtr);
  1269.         }
  1270.         status = (*devFsOpTable[DEV_TYPE_INDEX(devicePtr->type)].ioctl)
  1271.             (devicePtr, ioctlPtr, replyPtr);
  1272.         if (!(devHandlePtr->flags & FS_DEV_DONT_LOCK)) { 
  1273.         Fsutil_HandleUnlock(devHandlePtr);
  1274.         }
  1275.         break;
  1276.     }
  1277.     return(status);
  1278. }
  1279.  
  1280. /*
  1281.  *----------------------------------------------------------------------
  1282.  *
  1283.  * Fsio_DeviceGetIOAttr --
  1284.  *
  1285.  *      Get the I/O attributes for a device.  A copy of the access and
  1286.  *    modify times are kept at the I/O server.  This routine is called
  1287.  *    either from Fs_GetAttrStream or Fsrmt_RpcGetIOAttr to update
  1288.  *    the initial copy of the attributes obtained from the name server.
  1289.  *
  1290.  * Results:
  1291.  *    SUCCESS.
  1292.  *
  1293.  * Side effects:
  1294.  *    None.
  1295.  *
  1296.  *----------------------------------------------------------------------
  1297.  */
  1298. /*ARGSUSED*/
  1299. ReturnStatus
  1300. Fsio_DeviceGetIOAttr(fileIDPtr, clientID, attrPtr)
  1301.     Fs_FileID            *fileIDPtr;    /* FileID of device */
  1302.     int             clientID;    /* IGNORED */
  1303.     register Fs_Attributes    *attrPtr;    /* Attributes to update */
  1304. {
  1305.     register Fsio_DeviceIOHandle *devHandlePtr;
  1306.  
  1307.     devHandlePtr = Fsutil_HandleFetchType(Fsio_DeviceIOHandle, fileIDPtr);
  1308.     if (devHandlePtr != (Fsio_DeviceIOHandle *)NIL) {
  1309.     if (devHandlePtr->accessTime > attrPtr->accessTime.seconds) {
  1310.         attrPtr->accessTime.seconds = devHandlePtr->accessTime;
  1311.     }
  1312.     if (devHandlePtr->modifyTime > attrPtr->dataModifyTime.seconds) {
  1313.         attrPtr->dataModifyTime.seconds = devHandlePtr->modifyTime;
  1314.     }
  1315.     Fsutil_HandleRelease(devHandlePtr, TRUE);
  1316.     }
  1317.     return(SUCCESS);
  1318. }
  1319.  
  1320. /*
  1321.  *----------------------------------------------------------------------
  1322.  *
  1323.  * Fsio_DeviceSetIOAttr --
  1324.  *
  1325.  *      Set the I/O attributes for a device.  A copy of the access and
  1326.  *    modify times are kept at the I/O server.  This routine is called
  1327.  *    either from Fs_SetAttrStream or Fsrmt_RpcSetIOAttr to update
  1328.  *    the cached copy of the attributes.
  1329.  *
  1330.  * Results:
  1331.  *    SUCCESS.
  1332.  *
  1333.  * Side effects:
  1334.  *    None.
  1335.  *
  1336.  *----------------------------------------------------------------------
  1337.  */
  1338. /*ARGSUSED*/
  1339. ReturnStatus
  1340. Fsio_DeviceSetIOAttr(fileIDPtr, attrPtr, flags)
  1341.     Fs_FileID            *fileIDPtr;    /* FileID of device */
  1342.     register Fs_Attributes    *attrPtr;    /* Attributes to copy */
  1343.     int                flags;        /* What attrs to set */
  1344. {
  1345.     register Fsio_DeviceIOHandle *devHandlePtr;
  1346.  
  1347.     if (flags & FS_SET_TIMES) {
  1348.     devHandlePtr = Fsutil_HandleFetchType(Fsio_DeviceIOHandle, fileIDPtr);
  1349.     if (devHandlePtr != (Fsio_DeviceIOHandle *)NIL) {
  1350.         devHandlePtr->accessTime = attrPtr->accessTime.seconds;
  1351.         devHandlePtr->modifyTime = attrPtr->dataModifyTime.seconds;
  1352.         Fsutil_HandleRelease(devHandlePtr, TRUE);
  1353.     }
  1354.     }
  1355.     return(SUCCESS);
  1356. }
  1357.  
  1358.  
  1359. /*
  1360.  *----------------------------------------------------------------------
  1361.  *
  1362.  * Fsio_DevNotifyReader --
  1363.  *
  1364.  *    Fsio_DevNotifyReader is available to device driver interrupt handlers
  1365.  *    that need to notify waiting processes that the device is readable.
  1366.  *    It schedules a process level call to ReadNotify, which
  1367.  *    in turn iterates down the list of handles for the device waking up
  1368.  *    all read waiters.
  1369.  *
  1370.  * Results:
  1371.  *    None
  1372.  *
  1373.  * Side effects:
  1374.  *    Schedules a call to DevListNotify, which in turn calls
  1375.  *    Fsutil_WaitListNotify to schedule any waiting readers.
  1376.  *
  1377.  *----------------------------------------------------------------------
  1378.  */
  1379. void
  1380. Fsio_DevNotifyReader(notifyToken)
  1381.     Fs_NotifyToken notifyToken;
  1382. {
  1383.     register Fsio_DeviceIOHandle *devHandlePtr = (Fsio_DeviceIOHandle *)notifyToken;
  1384.  
  1385.     if ((devHandlePtr == (Fsio_DeviceIOHandle *)NIL) ||
  1386.     (devHandlePtr->notifyFlags & FS_READABLE)) {
  1387.     return;
  1388.     }
  1389.     if (devHandlePtr->hdr.fileID.type != FSIO_LCL_DEVICE_STREAM) {
  1390.     printf("Fsio_DevNotifyReader, bad handle\n");
  1391.     }
  1392.     devHandlePtr->notifyFlags |= FS_READABLE;
  1393.     Proc_CallFunc(ReadNotify, (ClientData) devHandlePtr, 0);
  1394. }
  1395.  
  1396. static void
  1397. ReadNotify(data, callInfoPtr)
  1398.     ClientData        data;
  1399.     Proc_CallInfo    *callInfoPtr;
  1400. {
  1401.     register Fsio_DeviceIOHandle *devHandlePtr = (Fsio_DeviceIOHandle *)data;
  1402.     if (devHandlePtr->hdr.fileID.type != FSIO_LCL_DEVICE_STREAM) {
  1403.     printf("ReadNotify, lost device handle\n");
  1404.     } else {
  1405.     devHandlePtr->notifyFlags &= ~FS_READABLE;
  1406.     Fsutil_WaitListNotify(&devHandlePtr->readWaitList);
  1407.     }
  1408.     callInfoPtr->interval = 0;
  1409. }
  1410.  
  1411.  
  1412. /*
  1413.  *----------------------------------------------------------------------
  1414.  *
  1415.  * Fsio_DevNotifyWriter --
  1416.  *
  1417.  *    Fsio_DevNotifyWriter is available to device driver interrupt handlers
  1418.  *    that need to notify waiting processes that the device is writeable.
  1419.  *    It schedules a process level call to Fs_WaitListNotifyStub on the
  1420.  *    devices's write wait list.
  1421.  *
  1422.  * Results:
  1423.  *    None
  1424.  *
  1425.  * Side effects:
  1426.  *    Schedules a call to Fs_WaitListNotifyStub.
  1427.  *
  1428.  *----------------------------------------------------------------------
  1429.  */
  1430. void
  1431. Fsio_DevNotifyWriter(notifyToken)
  1432.     Fs_NotifyToken notifyToken;
  1433. {
  1434.     register Fsio_DeviceIOHandle *devHandlePtr = (Fsio_DeviceIOHandle *)notifyToken;
  1435.  
  1436.     if ((devHandlePtr == (Fsio_DeviceIOHandle *)NIL) ||
  1437.     (devHandlePtr->notifyFlags & FS_WRITABLE)) {
  1438.     return;
  1439.     }
  1440.     if (devHandlePtr->hdr.fileID.type != FSIO_LCL_DEVICE_STREAM) {
  1441.     printf("Fsio_DevNotifyWriter, bad handle\n");
  1442.     return;
  1443.     }
  1444.     devHandlePtr->notifyFlags |= FS_WRITABLE;
  1445.     Proc_CallFunc(WriteNotify, (ClientData) devHandlePtr, 0);
  1446. }
  1447.  
  1448. static void
  1449. WriteNotify(data, callInfoPtr)
  1450.     ClientData        data;
  1451.     Proc_CallInfo    *callInfoPtr;
  1452. {
  1453.     register Fsio_DeviceIOHandle *devHandlePtr = (Fsio_DeviceIOHandle *)data;
  1454.     if (devHandlePtr->hdr.fileID.type != FSIO_LCL_DEVICE_STREAM) {
  1455.     printf( "WriteNotify, lost device handle\n");
  1456.     } else {
  1457.     devHandlePtr->notifyFlags &= ~FS_WRITABLE;
  1458.     Fsutil_WaitListNotify(&devHandlePtr->writeWaitList);
  1459.     }
  1460.     callInfoPtr->interval = 0;
  1461. }
  1462.  
  1463.  
  1464.  
  1465. /*
  1466.  *----------------------------------------------------------------------
  1467.  *
  1468.  * Fsio_DevNotifyException --
  1469.  *
  1470.  *    This is available to device driver interrupt handlers
  1471.  *    that need to notify waiting processes that there is an exception
  1472.  *    on the device.  This is only useful for processes waiting on
  1473.  *    exceptions in select.  This is not currently used.
  1474.  *    It schedules a process level call to Fs_WaitListNotifyStub on the
  1475.  *    devices's exception wait list.
  1476.  *
  1477.  * Results:
  1478.  *    None
  1479.  *
  1480.  * Side effects:
  1481.  *    Schedules a call to Fs_WaitListNotifyStub.
  1482.  *
  1483.  *----------------------------------------------------------------------
  1484.  */
  1485. void
  1486. Fsio_DevNotifyException(notifyToken)
  1487.     Fs_NotifyToken notifyToken;
  1488. {
  1489.     register Fsio_DeviceIOHandle *devHandlePtr = (Fsio_DeviceIOHandle *)notifyToken;
  1490.  
  1491.     if (devHandlePtr == (Fsio_DeviceIOHandle *)NIL) {
  1492.     return;
  1493.     }
  1494.     Proc_CallFunc(ExceptionNotify, (ClientData) devHandlePtr, 0);
  1495. }
  1496.  
  1497. static void
  1498. ExceptionNotify(data, callInfoPtr)
  1499.     ClientData        data;
  1500.     Proc_CallInfo    *callInfoPtr;
  1501. {
  1502.     register Fsio_DeviceIOHandle *devHandlePtr = (Fsio_DeviceIOHandle *)data;
  1503.     Fsutil_WaitListNotify(&devHandlePtr->exceptWaitList);
  1504.     callInfoPtr->interval = 0;
  1505. }
  1506.  
  1507.  
  1508. /*
  1509.  *----------------------------------------------------------------------
  1510.  *
  1511.  * Fsio_DeviceRecovTestUseCount --
  1512.  *
  1513.  *    For recovery testing, return the use count of the io handle.    
  1514.  *
  1515.  * Results:
  1516.  *    The use count.
  1517.  *
  1518.  * Side effects:
  1519.  *    None.
  1520.  *
  1521.  *----------------------------------------------------------------------
  1522.  */
  1523. int
  1524. Fsio_DeviceRecovTestUseCount(handlePtr)
  1525.     Fsio_DeviceIOHandle *handlePtr;
  1526. {
  1527.     return handlePtr->use.ref;
  1528. }
  1529.  
  1530. /*
  1531.  *----------------------------------------------------------------------
  1532.  *
  1533.  * Fsio_BootTimeTtyOpen --
  1534.  *
  1535.  *    This is a stripped down version of Fsio_DeviceIoOpen
  1536.  *    that is used to invoke the tty driver open routine
  1537.  *    at boot time.  The important thing to get right is
  1538.  *    that the tty driver has to be passed the real FS
  1539.  *    I/O handle for the device so notifications work.
  1540.  *
  1541.  * Results:
  1542.  *    SUCCESS or a device dependent open error code.
  1543.  *
  1544.  * Side effects:
  1545.  *    Sets up and installs the console's ioHandle.  The tty open
  1546.  *    routine is called so L1/break/F1 key processing for
  1547.  *    Dev_InvokeConsole command is enabled.
  1548.  *    The associated FS handle is unlocked
  1549.  *    upon exit, but its reference count has been incremented.
  1550.  *
  1551.  *----------------------------------------------------------------------
  1552.  */
  1553. ReturnStatus
  1554. Fsio_BootTimeTtyOpen()
  1555. {
  1556.     ReturnStatus     status;
  1557.     Fs_FileID        ttyFileID;
  1558.     Fsio_DeviceIOHandle    *devHandlePtr;
  1559.  
  1560.     /*
  1561.      * Set up the console's fileID.  This sets the console
  1562.      * unit number to 0, although this is cleverly mapped by the
  1563.      * ttyDriver to a serial line if the EEPROM is properly configured.
  1564.      */
  1565.     ttyFileID.type = FSIO_LCL_DEVICE_STREAM;
  1566.     ttyFileID.serverID = rpc_SpriteID;
  1567.     ttyFileID.major = DEV_TERM;
  1568.     ttyFileID.minor = 0;
  1569.     (void)FsioDeviceHandleInit(&ttyFileID, "/dev/console", &devHandlePtr);
  1570.     /*
  1571.      * The device driver open routine gets the device specification,
  1572.      * the useFlags, and a token passed to Fs_NotifyReader
  1573.      * or Fs_NotifyWriter when the device becomes ready for I/O.
  1574.      */
  1575.     if (DEV_TYPE_INDEX(devHandlePtr->device.type) >= devNumDevices) {
  1576.     status = FS_DEVICE_OP_INVALID;
  1577.     } else {
  1578.     int flags = 0;
  1579. /* XXX */ printf("Fsio_BootTimeTtyOpen: spriteID %d devHandle <%x>\n",
  1580.             rpc_SpriteID, devHandlePtr);
  1581.     status = (*devFsOpTable[DEV_TYPE_INDEX(devHandlePtr->device.type)].open)
  1582.             (&devHandlePtr->device, FS_READ|FS_WRITE, 
  1583.               (Fs_NotifyToken)devHandlePtr, &flags);
  1584.     }
  1585.     /*
  1586.      * Unlock the handle.  This leaves an extra reference just
  1587.      * to make sure the file system handle doesn't get scavenged.
  1588.      */
  1589.     Fsutil_HandleUnlock(devHandlePtr);
  1590.     return(status);
  1591. }
  1592.  
  1593.  
  1594. /*
  1595.  *----------------------------------------------------------------------
  1596.  *
  1597.  * Fsio_DeviceMmap --
  1598.  *
  1599.  *    Do a device-specific mmap operation.
  1600.  *
  1601.  * Results:
  1602.  *    SUCCESS or FAILURE.
  1603.  *
  1604.  * Side effects:
  1605.  *    Kernel memory mapped into user space.
  1606.  *
  1607.  *----------------------------------------------------------------------
  1608.  */
  1609. ReturnStatus
  1610. Fsio_DeviceMmap(streamPtr, startAddr, length, offset, newAddrPtr)
  1611.     Fs_Stream        *streamPtr;    /* Stream to device. */
  1612.     Address        startAddr;    /* Requested starting virt. addr. */
  1613.     int            length;        /* Length of mapped segment. */
  1614.     int            offset;        /* Offset into mapped file. */
  1615.     Address        *newAddrPtr;
  1616. {
  1617.     Fs_Device        *devicePtr;
  1618.     Fsio_DeviceIOHandle    *ioHandlePtr;
  1619.     ReturnStatus    status;
  1620.  
  1621.     if (streamPtr->ioHandlePtr->fileID.type != FSIO_LCL_DEVICE_STREAM) {
  1622.     printf("Fsio_DeviceMmap passed something that wasn't a device.\n");
  1623.     return FAILURE;
  1624.     }
  1625.     ioHandlePtr = (Fsio_DeviceIOHandle *) streamPtr->ioHandlePtr;
  1626.     devicePtr = &(ioHandlePtr->device);
  1627.     if (DEV_TYPE_INDEX(devicePtr->type) >= devNumDevices) {
  1628.     return  FS_DEVICE_OP_INVALID;
  1629.     }
  1630.  
  1631.     status = (*devFsOpTable[DEV_TYPE_INDEX(devicePtr->type)].mmap)
  1632.         (devicePtr, startAddr, length, offset, newAddrPtr);
  1633.  
  1634.     return status;
  1635. }
  1636.  
  1637.  
  1638. /*
  1639.  *----------------------------------------------------------------------
  1640.  *
  1641.  * Fsio_DeviceSetupHandle --
  1642.  *
  1643.  *    Given a device recovery object, setup the necessary handle state for it.
  1644.  *
  1645.  * Results:
  1646.  *    None.
  1647.  *
  1648.  * Side effects:
  1649.  *    A handle is created in put in the handle table.
  1650.  *
  1651.  *----------------------------------------------------------------------
  1652.  */
  1653. ReturnStatus
  1654. Fsio_DeviceSetupHandle(recovInfoPtr)
  1655.     Fsrecov_HandleState    *recovInfoPtr;
  1656. {
  1657.     Fs_FileID        fileID;
  1658.     int            clientID;
  1659.     Fsio_DeviceIOHandle    *devHandlePtr;
  1660.     int            flags;
  1661.     ReturnStatus    status;
  1662.     int            devIndex;
  1663.     Fsio_UseCounts    use;
  1664.  
  1665.     if (!recov_Transparent) {
  1666.     panic("Fsio_DeviceSetupHandle shouldn't have been called.");
  1667.     }
  1668.  
  1669.     fileID = recovInfoPtr->fileID;
  1670.     clientID = fileID.serverID;
  1671.     fileID.serverID = rpc_SpriteID;
  1672.     (void) FsioDeviceHandleInit(&fileID, (char *) NIL, &devHandlePtr);
  1673.  
  1674.     devIndex = DEV_TYPE_INDEX(devHandlePtr->device.type);
  1675.     if (devIndex >= devNumDevices) {
  1676.     Fsutil_HandleRelease(devHandlePtr, TRUE);
  1677.     return FS_DEVICE_OP_INVALID;
  1678.     }
  1679.  
  1680.     status = (*devFsOpTable[devIndex].reopen)(&devHandlePtr->device,
  1681.         recovInfoPtr->use.ref, recovInfoPtr->use.write,
  1682.         (Fs_NotifyToken) devHandlePtr, &flags);
  1683.     if (status != SUCCESS) {
  1684.     Fsutil_HandleRelease(devHandlePtr, TRUE);
  1685.     return FAILURE;
  1686.     }
  1687.  
  1688.     use.ref = recovInfoPtr->use.ref;
  1689.     use.write = recovInfoPtr->use.write;
  1690.     use.exec = 0;
  1691.  
  1692.     (void)Fsconsist_IOClientReopen(&devHandlePtr->clientList, clientID,
  1693.          &recovInfoPtr->use);
  1694.     devHandlePtr->use.ref += recovInfoPtr->use.ref;
  1695.     devHandlePtr->use.write += recovInfoPtr->use.write;
  1696.  
  1697.     Fsutil_HandleRelease(devHandlePtr, TRUE);
  1698.  
  1699.     return SUCCESS;
  1700. }
  1701.